﻿using System;
using System.Collections;
using System.IO;
using System.Threading;


namespace WITD
{
    /// <summary>
    /// A simple class for writing results of the calling program's work.
    /// </summary>
    class Logging
    {
        const String LogName = "WIT_Import_";
        const String LogEntry = "{0} : {1} WITD [ {4} ] from source project [ {2} ] to target project [ {3} ]";
        const String ErrorEntry = "Exception: {0}\n\n - While performing step: {1}";

        private ArrayList _results = new ArrayList();
        private string _logFileName;
        private StreamWriter LogFile;

        /// <summary>
        /// The collection of Strings to write to the log file.
        /// </summary>
        public ArrayList Results
        {
            get
            {
                return _results;
            }
        }

        /// <summary>
        /// Creates a new, uniquely named log file.
        /// </summary>
        public void CreateLogFile()
        {
            _logFileName = LogName + DateTime.Now.ToShortDateString().Replace("/", "-") + "_" + DateTime.Now.ToLongTimeString().Replace(":", "_").Replace(".", "_") + ".log";
            LogFile = new StreamWriter(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, _logFileName), false);
            LogFile.WriteLine("Log created at " + DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToLongTimeString() + LogFile.NewLine);
        }

        /// <summary>
        /// Flushes and closes the log file and ensures the system is ready for another iteration of work if requested.
        /// </summary>
        public void CleanupLog()
        {
            if (LogFile != null)
            {
                WriteLog(_results);
                LogFile.Flush();
                LogFile.Close();
                _results.Clear();
            }
        }

        /// <summary>
        /// Adds a String to the list of Strings to write to the log file.
        /// </summary>
        /// <param name="entry">The text to write to the ArrayList.</param>
        public void Add(string entry)
        {
            if (_results != null)
            {
                _results.Add(entry);
            }
        }

        /// <summary>
        /// Entry point for all logging.
        /// </summary>
        /// <param name="state">An <see cref="ImportProgress">ImportProgress</see> object with the current status of work.</param>
        public void Log(Object state)
        {
            System.Threading.ThreadPool.QueueUserWorkItem(new WaitCallback(DoLog), (ImportProgress)state);
        }

        /// <summary>
        /// A method to run in its own thread to log work. A separate thread is used to ensure log items do not get lost.
        /// </summary>
        /// <param name="state">An <see cref="ImportProgress">ImportProgress</see> object with the current status of work.</param>
        public void DoLog(Object state)
        {
            ImportProgress progress = (ImportProgress)state;
            if (!progress.UseLog) { return; }
            Exception newEx;
            String entry;
            DateTime logTime = DateTime.Now;

            if (LogFile != null)
            {
                if (!progress.HasErrors)
                {
                    if (progress.StatusText == "Done")
                    {
                        entry = progress.StatusText;
                    }
                    else
                    {
                        entry = String.Format(progress.FormatString,
                                              logTime.ToShortTimeString(),
                                              progress.StatusText,
                                              progress.SourceProject,
                                              progress.CurrentProject,
                                              progress.CurrentWIT, 
                                              progress.SourceCollection,
                                              progress.TargetCollection);
                    }
                }
                else
                {
                    if (progress.CurrentError == null)
                    {
                        progress.CurrentError = newEx = new Exception("Error");
                    }
                    else
                    {
                        newEx = progress.CurrentError;
                    }
                    entry = String.Format(ErrorEntry, newEx.Message,
                                                    String.Format(progress.FormatString,
                                                                    logTime.ToShortTimeString(),
                                                                    progress.StatusText,
                                                                    progress.SourceProject,
                                                                    progress.CurrentProject,
                                                                    progress.CurrentWIT, 
                                                                    progress.SourceCollection,
                                                                    progress.TargetCollection));
                }

                if (_results.Count > 0)
                {
                    if (!_results.Contains(entry))
                    {
                        _results.Add(entry);
                    }
                }
                else { _results.Add(entry); }
            }
        }

        /// <summary>
        /// Writes the contents of the specified ArrayList of Strings to the log file.
        /// </summary>
        /// <param name="results">0 or more Strings of text to write to the log file.</param>
        public void WriteLog(ArrayList results)
        {
            if (results != null && results.Count > 0)
            {
                if (LogFile == null || LogFile.BaseStream == null) { CreateLogFile(); }

                foreach (String item in results)
                {
                    LogFile.WriteLine(item);
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public void SelectLog()
        {
            System.Windows.Forms.OpenFileDialog dialog = new System.Windows.Forms.OpenFileDialog();
            dialog.DefaultExt = "log";
            dialog.Filter = "Log files (*.log)|*.log|All files (*.*)|*.*";
            dialog.InitialDirectory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);
            dialog.RestoreDirectory = true;
            dialog.Title = "Open log file";
            System.Windows.Forms.DialogResult result = dialog.ShowDialog();
            if (result == System.Windows.Forms.DialogResult.OK)
            {
                if (System.IO.File.Exists(dialog.FileName))
                {
                    LogViewer viewer = new LogViewer();
                    StreamReader reader = System.IO.File.OpenText(dialog.FileName);
                    viewer.txtLogContents.Text = reader.ReadToEnd();
                    if (String.IsNullOrEmpty(viewer.txtLogContents.Text))
                        viewer.txtLogContents.Text = "Log file is empty";
                    viewer.ShowDialog();
                }
                
            }


        }

    }
}
